Skip to content

Add PipeWire audio driver#111056

Open
j20001970 wants to merge 1 commit intogodotengine:masterfrom
j20001970:pipewire-audio
Open

Add PipeWire audio driver#111056
j20001970 wants to merge 1 commit intogodotengine:masterfrom
j20001970:pipewire-audio

Conversation

@j20001970
Copy link
Copy Markdown
Contributor

@j20001970 j20001970 commented Sep 30, 2025

Closes godotengine/godot-proposals#10723

This PR adds PipeWire audio driver for linuxbsd platform.

Distro support

This PR expects PipeWire version 1.0.0 or higher. Here is the non-exhaustive list of minimum Linux distribution version required for the driver to work.

Name libpipewire-0.3.so version
Alpine v3.19 1.0.0
Debian 13 1.4.2
Fedora 38 1.0.3
openSUSE Leap 15.6 1.0.5
Ubuntu 24.04 LTS 1.0.5

How to test the driver

The new PipeWire audio driver does not take precedence over existing PulseAudio driver at the moment. You can change audio/driver/driver to "PipeWire" in Project Settings, or use --audio-driver PipeWire arguments to test the driver.

Vendored PipeWire headers

This PR introduces new thirdparty headers to enable PipeWire support. A brief list of added PipeWire and SPA headers as of version 1.0.0 (the list may change if we update the headers in future) is documented to give a better grasp on how these headers are included.

Required by "pipewire/pipewire.h":
|───"pipewire/array.h"
|───"pipewire/client.h"
|───"pipewire/conf.h"
|───"pipewire/context.h"
|───"pipewire/device.h"
|───"pipewire/buffers.h"
|───"pipewire/core.h"
|───"pipewire/factory.h"
|───"pipewire/keys.h"
|───"pipewire/log.h"
|───"pipewire/loop.h"
|───"pipewire/link.h"
|───"pipewire/main-loop.h"
|───"pipewire/map.h"
|───"pipewire/mem.h"
|───"pipewire/module.h"
|───"pipewire/node.h"
|───"pipewire/properties.h"
|───"pipewire/proxy.h"
|───"pipewire/permission.h"
|───"pipewire/protocol.h"
|───"pipewire/port.h"
|───"pipewire/stream.h"
|───"pipewire/filter.h"
|───"pipewire/thread-loop.h"
|───"pipewire/data-loop.h"
|───"pipewire/type.h"
|───"pipewire/utils.h"
└───"pipewire/version.h"

SPA headers required by PipeWire:
|───"spa/buffer/buffer.h"
|   └───"spa/buffer/meta.h"
|───"spa/node/command.h"
|───"spa/node/io.h"
|───"spa/node/node.h"
|   └───"spa/node/event.h"
|       └───"spa/pod/event.h"
|───"spa/param/param.h"
|   |───"spa/param/buffers.h"
|   |───"spa/param/port-config.h"
|   |───"spa/param/profile.h"
|   └───"spa/param/route.h"
|───"spa/pod/command.h"
|───"spa/pod/pod.h"
|───"spa/support/log.h"
|───"spa/support/loop.h"
|   └───"spa/support/system.h"
|───"spa/support/plugin.h"
|───"spa/support/thread.h"
|───"spa/utils/defs.h"
|───"spa/utils/dict.h"
|───"spa/utils/hook.h"
|───"spa/utils/list.h"
|───"spa/utils/string.h"
└───"spa/utils/type.h"

Headers required by `AudioDriverPipeWire`:
|───"pipewire/extensions/metadata.h"
|───"spa/param/audio/raw.h" <- for SPA_AUDIO_FORMAT_* and SPA_AUDIO_CHANNEL_* enum
|───"spa/param/format.h" <- for SPA_FORMAT_AUDIO_* enum
|───"spa/pod/builder.h" <- for spa pod builder related functions and macros
|   |───"spa/pod/iter.h"
|   └───"spa/pod/vararg.h"
└───"spa/utils/keys.h"

@Nintorch
Copy link
Copy Markdown
Member

See also #109362 which may also add PipeWire support
Not to say your PR is worse or anything, just wanted to let you know about this PR too :)
But I'm not sure which one may be better or worse, or just different.

@j20001970 j20001970 force-pushed the pipewire-audio branch 3 times, most recently from 018674e to 4d5ab14 Compare October 1, 2025 09:54
@j20001970
Copy link
Copy Markdown
Contributor Author

I rebased the commits so that this PR no longer depends on #109500.

@j20001970 j20001970 marked this pull request as ready for review October 1, 2025 09:58
@j20001970 j20001970 requested review from a team as code owners October 1, 2025 09:58
@j20001970 j20001970 force-pushed the pipewire-audio branch 13 times, most recently from 65505a9 to 4b41930 Compare October 8, 2025 14:12
@j20001970 j20001970 force-pushed the pipewire-audio branch 2 times, most recently from fe2c0f9 to f1c07ca Compare January 13, 2026 09:29
@j20001970
Copy link
Copy Markdown
Contributor Author

f1c07cad65925fa942086cbae37c27d858af8d90 now uses print_verbose instead of ERR_FAIL_NULL_V macro if pw_context_connect failed in AudioDriverPipeWire::init, this is for suppressing errors on audio driver fallback when PipeWire library meets version requirement but the socket is not accessible.

@j20001970 j20001970 force-pushed the pipewire-audio branch 2 times, most recently from 777b476 to 343a871 Compare January 27, 2026 16:47
@j20001970 j20001970 force-pushed the pipewire-audio branch 2 times, most recently from 0ad83d7 to 2a060a2 Compare February 14, 2026 16:44
@j20001970 j20001970 force-pushed the pipewire-audio branch 2 times, most recently from 9a306e1 to c5ddbdf Compare March 16, 2026 09:30
@akien-mga
Copy link
Copy Markdown
Member

akien-mga commented Mar 17, 2026

Tested briefly on Fedora 43 (using PipeWire as audio server with default config) and it seems to work fine. I haven't reviewed the code yet.

How to validate that it's indeed using PipeWire directly and not via the pipewire-pulse plugin?

What kind of benefits are expected from this new driver, aside from sidestepping pipewire-pulse on systems defaulting to PipeWire?

Edit: I just read the proposal in godotengine/godot-proposals#10723. It mentions lacking audio input in ALSA, and too much latency in PulseAudio. Does this PR solve those two shortcomings?


Regarding the vendored headers in thirdparty/linuxbsd_headers/pipewire/, there's quite a lot of them. If possible, we like to trim down which thirdparty files we vendor to the minimum subset needed by Godot. I asked Copilot to assess which files could be safely removed and it came up with this: akien-mga@f8efbd3

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
                       Files        Lines         Code     Comments       Blanks
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 Before                  205        27222        16279         6702         4241
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 After                    79        13007         7115         3916         1976
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

The downside is that we'd have to document which files should be copied / removed when updating the library.

@Damglador
Copy link
Copy Markdown

I check if a program is using pipewire directly by doing pw-dump > ~/pw-dump, searching for the program's binary name in the file and checking its "client.api", if there is no "client.api" for the program - it's using pipewire directly.

@j20001970
Copy link
Copy Markdown
Contributor Author

What kind of benefits are expected from this new driver, aside from sidestepping pipewire-pulse on systems defaulting to PipeWire?

If I did the profiling correctly, we can expect the new driver having much lower driver time (audio_driver in EngineDebugger) when compared with existing PulseAudio driver, and the new driver also implements audio input that ALSA driver lacks, which should solve both issues mentioned in godotengine/godot-proposals#10723.

If possible, we like to trim down which thirdparty files we vendor to the minimum subset needed by Godot.

That makes sense, I'll try to trim down unused headers in next push.

@j20001970 j20001970 force-pushed the pipewire-audio branch 5 times, most recently from 3bd20d5 to f22e4eb Compare March 19, 2026 05:35
@j20001970 j20001970 force-pushed the pipewire-audio branch 2 times, most recently from 16cd0c4 to 48d4c22 Compare April 1, 2026 01:50
@ArchercatNEO
Copy link
Copy Markdown
Contributor

Are we ready for the next round of review?

@j20001970
Copy link
Copy Markdown
Contributor Author

j20001970 commented Apr 12, 2026

Are we ready for the next round of review?

The PR is ready for the next round of review. Should I re-request the review, or wait for the reviewers?

@ArchercatNEO
Copy link
Copy Markdown
Contributor

I think re-requesting a review would be good, I asked on RocketChat for a review and that's how the previous round happened. Calinou also said he'd review but I haven't seen him so I think you could ping him too when asking for review

@j20001970
Copy link
Copy Markdown
Contributor Author

Hi @Calinou, can you help reviewing this PR? Thank you in advance!

Copy link
Copy Markdown
Member

@Calinou Calinou left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested locally on Fedora 43, it mostly works as expected.

Some feedback:

$ pw-dump > ~/pw-dump
$ rg -i "platformer" pw-dump
10101:        "application.name": "Platformer 2D",
10168:        "node.name": "Platformer 2D",
10563:        "object.path": "Platformer 2D:output_0",
10565:        "port.alias": "Platformer 2D:output_FL",
10648:        "object.path": "Platformer 2D:output_1",
10650:        "port.alias": "Platformer 2D:output_FR",
  • Audio input doesn't seem to work in the Mic Record demo (nothing is recorded, and the app doesn't appear in the list of recording applications). In comparison, it works in PulseAudio (but not in ALSA).

  • PipeWire sounds noticeably quieter than PulseAudio/ALSA. I double-checked all audio drivers are at 100% for the per-app volume in the system settings.

Music from the Platformer 2D demo run through PulseAudio, ALSA, then PipeWire:

pulseaudio_alsa_pipewire.mp3

Waveform of the above audio normalized in Audacity for easier comparison (from left to right: PulseAudio, ALSA, PipeWire):

Image
  • I haven't done latency testing since I don't have the hardware for it currently, but it would be good to investigate this in the future.

@j20001970
Copy link
Copy Markdown
Contributor Author

Tested locally on Fedora 43, it mostly works as expected.

Some feedback:

* PipeWire appears to be used natively, according to the [above instructions](https://github.com/godotengine/godot/pull/111056#issuecomment-4074777513):
$ pw-dump > ~/pw-dump
$ rg -i "platformer" pw-dump
10101:        "application.name": "Platformer 2D",
10168:        "node.name": "Platformer 2D",
10563:        "object.path": "Platformer 2D:output_0",
10565:        "port.alias": "Platformer 2D:output_FL",
10648:        "object.path": "Platformer 2D:output_1",
10650:        "port.alias": "Platformer 2D:output_FR",
* Audio input doesn't seem to work in the [Mic Record](https://github.com/godotengine/godot-demo-projects/tree/master/audio/mic_record) demo (nothing is recorded, and the app doesn't appear in the list of recording applications). In comparison, it works in PulseAudio (but not in ALSA).

* PipeWire sounds noticeably quieter than PulseAudio/ALSA. I double-checked all audio drivers are at 100% for the per-app volume in the system settings.

Music from the Platformer 2D demo run through PulseAudio, ALSA, then PipeWire:

pulseaudio_alsa_pipewire.mp3

Waveform of the above audio normalized in Audacity for easier comparison (from left to right: PulseAudio, ALSA, PipeWire):
Image

* I haven't done latency testing since I don't have the hardware for it currently, but it would be good to investigate this in the future.

Thanks for the review, the PR has been updated to 506940f with the following change:

  • Audio position for input stream has been added (the primary reason why input stream didn't work as expected).
  • When initializing input stream, set_input_device("Default") is called to update input channel count.
  • Init / Start logic for output stream has been updated to remove the redundant active SafeFlag from the driver.

For the volume issue across different drivers, I can't seem to reproduce the same problem. The default per-app volume can be different when switching to different driver, but the waveform magnitude looks like the same when comparing with PulseAudio(first) and PipeWire(second) at 100% volume. More testing might be needed for this part.

Copy link
Copy Markdown
Member

@Calinou Calinou left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Audio input works on my end now. Code looks good to me.

I can still reproduce the different volume on PipeWire, but as per the above comment, it's likely system-specific. I consider this PR good on my end, but I still would like it to get testing on more configurations (especially 3.1/5.1/7.1 for people who have access to such a setup).

Note that this PR uses C++20 features (designated initializers), but we considered this to be acceptable in Wayland code as it's only compiled on Linux/*BSD. Similarly, the PipeWire audio driver is Linux/*BSD-only code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Adding a native PipeWire audio driver

8 participants